
// Copyright (C) 2012 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Xml;
using Derm.Render;

namespace Derm.Xml.Collada
{
	/// <summary>
	/// A constant float value of a referenced parameter.
	/// </summary>
	public class ColladaFxCommonFloatOrParamType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonFloatOrParamType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonFloatOrParamType.
		/// </param>
		public ColladaFxCommonFloatOrParamType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX FloatOrParam Type Information

		/// <summary>
		/// The float value.
		/// </summary>
		public ColladaTargetableFloat Float;

		/// <summary>
		/// The paramater reference.
		/// </summary>
		public string ParamRef;

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementFloat) {
				Float = new ColladaTargetableFloat(this);
				Float.ReadXml(xmlReader);
			} else if (elementName == ColladaElementParam) {
				string attribute;

				// Parse inline 'ref' attribute
				if ((attribute = xmlReader[ColladaAttributeParamRef]) == null)
					throw new InvalidOperationException("required attribute " + ColladaAttributeParamRef);
				ParamRef = attribute;

				// Skip element
				XmlHelper.SkipXmlElement(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'common_float_or_param_type' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat = "float";

		/// <summary>
		/// Collada 'common_float_or_param_type' child element name (1.4).
		/// </summary>
		private const string ColladaElementParam = "param";

		/// <summary>
		/// Collada 'common_float_or_param_type/param' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeParamRef = "ref";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonColorType : ColladaFxColorType
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonColorType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonColorType.
		/// </param>
		public ColladaFxCommonColorType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Color Type Information

		/// <summary>
		/// The sid attribute is a text string value containing the sub-identifier of this element. 
		/// This value must be unique within the scope of the parent element. Optional attribute.
		/// </summary>
		public string Sid;

		#endregion

		#region ColladaFxColorType Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeSid]) != null)
				Sid = attribute;
		}

		/// <summary>
		/// Collada 'common_color_or_texture_type/color' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeSid = "sid";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonTextureType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonTextureType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonTextureType.
		/// </param>
		public ColladaFxCommonTextureType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Texture Type Information

		/// <summary>
		/// Texture.
		/// </summary>
		public string Texture;

		/// <summary>
		/// Texture coordinate.
		/// </summary>
		public string TexCoord;

		/// <summary>
		/// The extra element may appear any number of times.
		/// </summary>
		public List<ColladaExtra>  Extras = new List<ColladaExtra>();

		#endregion

		#region COLLADA Support

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeTexture]) == null)
				throw new InvalidOperationException("required attribute " + ColladaAttributeTexture);
			Texture = attribute;

			if ((attribute = xmlReader[ColladaAttributeTexCoord]) == null)
				throw new InvalidOperationException("required attribute " + ColladaAttributeTexCoord);
			TexCoord = attribute;
		}


		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementTexExtra) {
				ColladaExtra colladaExtra = new ColladaExtra(this);
				colladaExtra.ReadXml(xmlReader);
				Extras.Add(colladaExtra);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'common_color_or_texture_type/texture' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeTexture = "texture";

		/// <summary>
		/// Collada 'common_color_or_texture_type/texture' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeTexCoord = "texcoord";

		/// <summary>
		/// Collada 'common_color_or_texture_type/texture' child element name (1.4).
		/// </summary>
		private const string ColladaElementTexExtra = "extra";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonColorOrTextureType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonColorOrTextureType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonColorOrTextureType.
		/// </param>
		public ColladaFxCommonColorOrTextureType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX ColorOrTexture Type Information

		/// <summary>
		/// A constant color.
		/// </summary>
		public ColladaFxCommonColorType Color;

		/// <summary>
		/// A referenced parameter.
		/// </summary>
		public string ParamRef;

		/// <summary>
		/// A texture.
		/// </summary>
		public ColladaFxCommonTextureType Texture;
		
		#endregion

		#region COLLADA Support

		/// <summary>
		/// Determine whether this parameter specify a fixed/constant color.
		/// </summary>
		public bool IsFixedColor
		{
			get { return (Texture == null); }
		}

		/// <summary>
		/// Determine whether this parameter specify a varying color.
		/// </summary>
		public bool IsTextureColor
		{
			get { return (Texture != null); }
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public ColorRGBAF GetFixedColor()
		{
			if (IsFixedColor == false)
				throw new InvalidOperationException("no fixed color");

			return (Color.Value);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public Texture GetTexture()
		{
			if (IsTextureColor == false)
				throw new InvalidOperationException("no texture");

			ColladaFxProfile colladaProfile = (ColladaFxProfile) GetParent(delegate(ColladaXmlSerializable node)
           	{
           		return (node.GetType() == typeof(ColladaFxCommonProfile));
           	});

			switch (colladaProfile.ProfileName) {
				case ColladaFxCommonProfile.Profile:
					{
						ColladaFxCommonProfile commonProfile = (ColladaFxCommonProfile) colladaProfile;
						ColladaFxCommonNewParamType samplerParam = commonProfile.NewParams.Find(delegate(ColladaFxCommonNewParamType param)
                     	{
							return (param.Sid == Texture.Texture);
                     	});

						if (samplerParam == null)
							throw new InvalidOperationException("no sampler found");

						ColladaFxSampler sampler = (ColladaFxSampler) samplerParam.Value.Value;

						return (sampler.Create());
					}
					break;
				default:
					throw new NotSupportedException("not supported profile " + colladaProfile.ProfileName);
			}
		}

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementColor) {
				Color = new ColladaFxCommonColorType(this);
				Color.ReadXml(xmlReader);
			} else if (elementName == ColladaElementParam) {
				string attribute;

				// Parse inline 'ref' attribute
				if ((attribute = xmlReader[ColladaAttributeParamRef]) == null)
					throw new InvalidOperationException("required attribute " + ColladaAttributeParamRef);
				ParamRef = attribute;

				// Skip element
				XmlHelper.SkipXmlElement(xmlReader);
			} else if (elementName == ColladaElementTexture) {
				Texture = new ColladaFxCommonTextureType(this);
				Texture.ReadXml(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'common_color_or_texture_type' child element name (1.4).
		/// </summary>
		private const string ColladaElementColor = "color";

		/// <summary>
		/// Collada 'common_color_or_texture_type' child element name (1.4).
		/// </summary>
		private const string ColladaElementParam = "param";

		/// <summary>
		/// Collada 'common_color_or_texture_type/param' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeParamRef = "ref";

		/// <summary>
		/// Collada 'common_color_or_texture_type' child element name (1.4).
		/// </summary>
		private const string ColladaElementTexture = "texture";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonTransparentType : ColladaFxCommonColorOrTextureType
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonTransparentType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonTransparentType.
		/// </param>
		public ColladaFxCommonTransparentType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxOpaqueType Opaque = ColladaFxOpaqueType.AlphaOne;

		#region ColladaXmlSerializable Overrides

		

		#endregion
	}

	/// <summary>
	/// This element creates a new, named param object in the FX Runtime, assigns it a type, an initial value, and additional attributes at declaration time.
	/// </summary>
	public class ColladaFxCommonNewParamType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonNewParamType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonNewParamType.
		/// </param>
		public ColladaFxCommonNewParamType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Profile NewParam Type

		/// <summary>
		/// The sid attribute is a text string value containing the sub-identifier of this element. 
		/// This value must be unique within the scope of the parent element. Required attribute.
		/// </summary>
		public string Sid;

		/// <summary>
		/// The semantic element allows you to specify a semantic for this new param.
		/// </summary>
		public string Semantic;

		/// <summary>
		/// The modifier element allows you to specify a modifier for this new param.
		/// </summary>
		public ColladaFxModifier Modifier = ColladaFxModifier.None;

		/// <summary>
		/// The parameter value (required element).
		/// </summary>
		public ColladaFxBasicType Value;

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeSid]) != null)
				Sid = attribute;
		}

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementSemantic) {
				Semantic = XmlHelper.ReadXmlTextElement(xmlReader);
			} else if (elementName == ColladaElementModifier) {
				Modifier = XmlHelper.ReadXmlEnum<ColladaFxModifier>(XmlHelper.ReadXmlTextElement(xmlReader));
			} else if (ColladaFxBasicType.IsKnownElement(elementName)) {

				// This is somewhat a special case: should we derive from ColladaFxBasicType?

				Value = new ColladaFxBasicType(this);
				Value.ReadElement(elementName, xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'fx_newparam_common' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeSid = "sid";

		/// <summary>
		/// Collada 'fx_newparam_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementSemantic = "semantic";

		/// <summary>
		/// Collada 'fx_newparam_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementModifier = "modifier";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public abstract class ColladaFxCommonProfileTechniqueModel : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfileTechniqueModel.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfileTechniqueModel.
		/// </param>
		protected ColladaFxCommonProfileTechniqueModel(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Profile Technique Model Information

		/// <summary>
		/// Emiision color.
		/// </summary>
		public ColladaFxCommonColorOrTextureType Emission;

		/// <summary>
		/// Reflective color.
		/// </summary>
		public ColladaFxCommonColorOrTextureType Reflective;

		/// <summary>
		/// Reflectivity.
		/// </summary>
		public ColladaFxCommonFloatOrParamType Reflectivity;

		/// <summary>
		/// Transparency.
		/// </summary>
		public ColladaFxCommonTransparentType Transparent;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxCommonFloatOrParamType Transparency;

		/// <summary>
		/// Index of reflection.
		/// </summary>
		public ColladaFxCommonFloatOrParamType IndexOfRefraction;

		#endregion

		#region COLLADA Support

		/// <summary>
		/// Modify a set of parameters defining an effect.
		/// </summary>
		/// <param name="shaderParameters">
		/// A <see cref="ColladaShaderParameters"/> that hols the current parameters for defining a
		/// COLLADA effect.
		/// </param>
		internal virtual void CompileShaderParameters(ColladaShaderParameters shaderParameters)
		{
			//throw new NotImplementedException(GetType() + " has not implemented CompileShaderParameters");
		}

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementEmission) {
				Emission = new ColladaFxCommonColorOrTextureType(this);
				Emission.ReadXml(xmlReader);
			} else if (elementName == ColladaElementReflective) {
				Reflective = new ColladaFxCommonColorOrTextureType(this);
				Reflective.ReadXml(xmlReader);
			} else if (elementName == ColladaElementReflectivity) {
				Reflectivity = new ColladaFxCommonFloatOrParamType(this);
				Reflectivity.ReadXml(xmlReader);
			} else if (elementName == ColladaElementTransparent) {
				Transparent = new ColladaFxCommonTransparentType(this);
				Transparent.ReadXml(xmlReader);
			} else if (elementName == ColladaElementTransparency) {
				Transparency = new ColladaFxCommonFloatOrParamType(this);
				Transparency.ReadXml(xmlReader);
			} else if (elementName == ColladaElementIndexOfRefraction) {
				IndexOfRefraction = new ColladaFxCommonFloatOrParamType(this);
				IndexOfRefraction.ReadXml(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'profile_COMMON/technique/[color|lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementEmission = "emission";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[color|lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementReflective = "reflective";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[color|lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementReflectivity = "reflectivity";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[color|lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementTransparent = "transparent";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[color|lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementTransparency = "transparency";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[color|lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementIndexOfRefraction = "index_of_refraction";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonProfileTechniqueConstant : ColladaFxCommonProfileTechniqueModel
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfileTechniqueConstant.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfileTechniqueConstant.
		/// </param>
		public ColladaFxCommonProfileTechniqueConstant(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonProfileTechniqueLambert : ColladaFxCommonProfileTechniqueModel
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfileTechniqueLambert.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfileTechniqueLambert.
		/// </param>
		public ColladaFxCommonProfileTechniqueLambert(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Profile Technique Lambert

		/// <summary>
		/// Ambient color.
		/// </summary>
		public ColladaFxCommonColorOrTextureType Ambient;

		/// <summary>
		/// Diffuse color.
		/// </summary>
		public ColladaFxCommonColorOrTextureType Diffuse;

		#endregion

		#region ColladaFxCommonProfileTechniqueModel Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementAmbient) {
				Ambient = new ColladaFxCommonColorOrTextureType(this);
				Ambient.ReadXml(xmlReader);
			} else if (elementName == ColladaElementDiffuse) {
				Diffuse = new ColladaFxCommonColorOrTextureType(this);
				Diffuse.ReadXml(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Modify a set of parameters defining an effect.
		/// </summary>
		/// <param name="shaderParameters">
		/// A <see cref="ColladaShaderParameters"/> that hols the current parameters for defining a
		/// COLLADA effect.
		/// </param>
		internal override void CompileShaderParameters(ColladaShaderParameters shaderParameters)
		{
			if (shaderParameters == null)
				throw new ArgumentNullException("shaderParameters");

			if (IsFragmentLightingRequired() == false && false) {
				// Effect parameter: shader program preprocessor symbol
				shaderParameters.ShaderCompiler.DefineSymbol("DS_LIGHTING_PER_VERTEX");
				// Effect parameter: shader program additional object
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.PhongShading", ShaderObject.Stage.Vertex);
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.LightStateShader", ShaderObject.Stage.Vertex);
			} else {
				// Effect parameter: shader program preprocessor symbol
				shaderParameters.ShaderCompiler.DefineSymbol("DS_LIGHTING_PER_FRAGMENT");
				// Effect parameter: shader program additional object
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.LambertShading", ShaderObject.Stage.Fragment);
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.LightStateShader", ShaderObject.Stage.Fragment);
			}

			// Effect parameter: shader program uniform state "Material"
			MaterialState materialState = new MaterialState();
			materialState.FrontMaterial = new Material();
			if ((Emission != null) && (Emission.IsFixedColor))
				materialState.FrontMaterial.EmissiveColor = Emission.GetFixedColor();

			if ((Diffuse != null) && (Diffuse.IsFixedColor))
				materialState.FrontMaterial.DiffuseColor = Diffuse.GetFixedColor();
			if ((Diffuse != null) && (Diffuse.IsTextureColor)) {
				materialState.FrontMaterialTextures.DiffuseTexture = Diffuse.GetTexture();
				materialState.FrontMaterialTextures.DiffuseTextureTextCoord = 0;
			}

			shaderParameters.RenderState.DefineState(materialState);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		private bool IsFragmentLightingRequired()
		{
			if ((Diffuse != null) && (Diffuse.IsTextureColor))
				return (true);

			return (false);
		}

		/// <summary>
		/// Collada 'profile_COMMON/technique/[lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementAmbient = "ambient";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[lambert|phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementDiffuse = "diffuse";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonProfileTechniquePhong : ColladaFxCommonProfileTechniqueLambert
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfileTechniquePhong.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfileTechniquePhong.
		/// </param>
		public ColladaFxCommonProfileTechniquePhong(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Profile Technique Phong

		/// <summary>
		/// Specular color.
		/// </summary>
		public ColladaFxCommonColorOrTextureType Specular;

		/// <summary>
		/// Shiness.
		/// </summary>
		public ColladaFxCommonFloatOrParamType Shiness;

		#endregion

		#region ColladaFxCommonProfileTechniqueLambert Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementSpecular) {
				Specular = new ColladaFxCommonColorOrTextureType(this);
				Specular.ReadXml(xmlReader);
			} else if (elementName == ColladaElementShiness) {
				Shiness = new ColladaFxCommonFloatOrParamType(this);
				Shiness.ReadXml(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Modify a set of parameters defining an effect.
		/// </summary>
		/// <param name="shaderParameters">
		/// A <see cref="ColladaShaderParameters"/> that hols the current parameters for defining a
		/// COLLADA effect.
		/// </param>
		internal override void CompileShaderParameters(ColladaShaderParameters shaderParameters)
		{
			if (shaderParameters == null)
				throw new ArgumentNullException("shaderParameters");

			if (IsFragmentLightingRequired() == false && false) {
				// Effect parameter: shader program preprocessor symbol
				shaderParameters.ShaderCompiler.DefineSymbol("DS_LIGHTING_PER_VERTEX");
				// Effect parameter: shader program additional object
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.PhongShading", ShaderObject.Stage.Vertex);
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.LightStateShader", ShaderObject.Stage.Vertex);
			} else {
				// Effect parameter: shader program preprocessor symbol
				shaderParameters.ShaderCompiler.DefineSymbol("DS_LIGHTING_PER_FRAGMENT");
				// Effect parameter: shader program additional object
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.PhongShading", ShaderObject.Stage.Fragment);
				shaderParameters.ShaderProgram.AttachShader("Derm.Light.LightStateShader", ShaderObject.Stage.Fragment);
			}

			// Effect parameter: shader program uniform state "Material"
			MaterialState materialState = new MaterialState();
			materialState.FrontMaterial = new Material();
			if ((Emission != null) && (Emission.IsFixedColor))
				materialState.FrontMaterial.EmissiveColor = Emission.GetFixedColor();

			if ((Diffuse != null) && (Diffuse.IsFixedColor))
				materialState.FrontMaterial.DiffuseColor = Diffuse.GetFixedColor();
			if ((Diffuse != null) && (Diffuse.IsTextureColor)) {
				materialState.FrontMaterialTextures.DiffuseTexture = Diffuse.GetTexture();
				materialState.FrontMaterialTextures.DiffuseTextureTextCoord = 0;
			}

			if ((Specular != null) && (Specular.IsFixedColor))
				materialState.FrontMaterial.SpecularColor = Specular.GetFixedColor();
			if (Shiness != null)
				materialState.FrontMaterial.Shininess = Shiness.Float.Value;
			shaderParameters.RenderState.DefineState(materialState);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		private bool IsFragmentLightingRequired()
		{
			if ((Diffuse != null) && (Diffuse.IsTextureColor))
				return (true);

			return (false);
		}

		/// <summary>
		/// Collada 'profile_COMMON/technique/[phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementSpecular = "specular";

		/// <summary>
		/// Collada 'profile_COMMON/technique/[phong|blinn]' child element name (1.4).
		/// </summary>
		private const string ColladaElementShiness = "shininess";

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxCommonProfileTechniqueBlinn : ColladaFxCommonProfileTechniquePhong
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfileTechniqueBlinn.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfileTechniqueBlinn.
		/// </param>
		public ColladaFxCommonProfileTechniqueBlinn(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion
	}

	/// <summary>
	/// Holds a description of the textures, samplers, shaders, parameters, and passes necessary for rendering this effect using one method.
	/// </summary>
	public class ColladaFxCommonProfileTechnique : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfileTechnique.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfileTechnique.
		/// </param>
		public ColladaFxCommonProfileTechnique(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Profile Technique Information

		/// <summary>
		/// The id attribute is a text string containing the unique identifier of this element. 
		/// This value must be unique within the instance document. Optional attribute.
		/// </summary>
		public string Id;

		/// <summary>
		/// The sid attribute is a text string value containing the sub-identifier of this element. 
		/// This value must be unique within the scope of the parent element. Required attribute.
		/// </summary>
		public string Sid;

		/// <summary>
		/// The technique element may contain an asset element.
		/// </summary>
		public ColladaAsset Asset;

		/// <summary>
		/// 
		/// </summary>
		public List<ColladaImage> Images = new List<ColladaImage>();

		/// <summary>
		/// 
		/// </summary>
		public List<ColladaFxCommonNewParamType> NewParams = new List<ColladaFxCommonNewParamType>();

		/// <summary>
		/// Common model.
		/// </summary>
		public ColladaFxCommonProfileTechniqueModel Model;

		/// <summary>
		/// The extra element may appear any number of times.
		/// </summary>
		public List<ColladaExtra> Extras = new List<ColladaExtra>();

		#endregion

		#region COLLADA Support

		/// <summary>
		/// Modify a set of parameters defining an effect.
		/// </summary>
		/// <param name="shaderParameters">
		/// A <see cref="ColladaShaderParameters"/> that hols the current parameters for defining a
		/// COLLADA effect.
		/// </param>
		internal void CompileShaderParameters(ColladaShaderParameters shaderParameters)
		{
			if (shaderParameters == null)
				throw new ArgumentNullException("shaderParameters");

			// Model parameters
			Model.CompileShaderParameters(shaderParameters);
		}

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeId]) != null)
				Id = attribute;
			if ((attribute = xmlReader[ColladaAttributeSid]) != null)
				Sid = attribute;
		}

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementAsset) {
				Asset = new ColladaAsset(this);
				Asset.ReadXml(xmlReader);
			} else if (elementName == ColladaElementImage) {
				ColladaImage colladaImage = new ColladaImage(this);
				colladaImage.ReadXml(xmlReader);
				Images.Add(colladaImage);
			} else if (elementName == ColladaElementNewParam) {
				ColladaFxCommonNewParamType colladaNewParam = new ColladaFxCommonNewParamType(this);
				colladaNewParam.ReadXml(xmlReader);
				NewParams.Add(colladaNewParam);
			} else if (elementName == ColladaElementConstant) {
				Model = new ColladaFxCommonProfileTechniqueConstant(this);
				Model.ReadXml(xmlReader);
			} else if (elementName == ColladaElementLambert) {
				Model = new ColladaFxCommonProfileTechniqueLambert(this);
				Model.ReadXml(xmlReader);
			} else if (elementName == ColladaElementPhong) {
				Model = new ColladaFxCommonProfileTechniquePhong(this);
				Model.ReadXml(xmlReader);
			} else if (elementName == ColladaElementBlinn) {
				Model = new ColladaFxCommonProfileTechniqueBlinn(this);
				Model.ReadXml(xmlReader);
			} else if (elementName == ColladaElementExtra) {
				ColladaExtra colladaExtra = new ColladaExtra(this);
				colladaExtra.ReadXml(xmlReader);
				Extras.Add(colladaExtra);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'profile_COMMON/technique' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeId = "id";

		/// <summary>
		/// Collada 'profile_COMMON/technique' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeSid = "sid";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementAsset = "asset";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementImage = "image";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementNewParam = "newparam";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementConstant = "constant";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementLambert = "lambert";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementPhong = "phong";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementBlinn = "blinn";

		/// <summary>
		/// Collada 'profile_COMMON/technique' child element name (1.4).
		/// </summary>
		private const string ColladaElementExtra = "extra";

		#endregion
	}

	/// <summary>
	/// Opens a block of COMMON platform-specific data types and technique declarations.
	/// </summary>
	public class ColladaFxCommonProfile : ColladaFxProfile
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxCommonProfile.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxCommonProfile.
		/// </param>
		public ColladaFxCommonProfile(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Profile Information

		/// <summary>
		/// The id attribute is a text string containing the unique identifier of this element. 
		/// This value must be unique within the instance document. Optional attribute.
		/// </summary>
		public string Id;

		/// <summary>
		/// The COMMON element may contain an asset element.
		/// </summary>
		public ColladaAsset Asset;

		/// <summary>
		/// 
		/// </summary>
		public readonly List<ColladaImage> Images = new List<ColladaImage>();

		/// <summary>
		/// 
		/// </summary>
		public readonly List<ColladaFxCommonNewParamType> NewParams = new List<ColladaFxCommonNewParamType>();

		/// <summary>
		/// Holds a description of the textures, samplers, shaders, parameters, and passes necessary for rendering
		/// this effect using one method.
		/// </summary>
		public ColladaFxCommonProfileTechnique Technique;

		/// <summary>
		/// The extra element may appear any number of times.
		/// </summary>
		public readonly List<ColladaExtra> Extras = new List<ColladaExtra>();

		#endregion

		#region ColladaFxProfile Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeId]) != null)
				Id = attribute;
		}

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementAsset) {
				Asset = new ColladaAsset(this);
				Asset.ReadXml(xmlReader);
			} else if (elementName == ColladaElementImage) {
				ColladaImage colladaImage = new ColladaImage(this);
				colladaImage.ReadXml(xmlReader);
				Images.Add(colladaImage);
			} else if (elementName == ColladaElementNewParam) {
				ColladaFxCommonNewParamType colladaNewParam = new ColladaFxCommonNewParamType(this);
				colladaNewParam.ReadXml(xmlReader);
				NewParams.Add(colladaNewParam);
			} else if (elementName == ColladaElementTechnique) {
				Technique = new ColladaFxCommonProfileTechnique(this);
				Technique.ReadXml(xmlReader);
			} else if (elementName == ColladaElementExtra) {
				ColladaExtra colladaExtra = new ColladaExtra(this);
				colladaExtra.ReadXml(xmlReader);
				Extras.Add(colladaExtra);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// The name that identifies this profile.
		/// </summary>
		internal const string Profile = "COMMON";

		/// <summary>
		/// The name that identifies this profile.
		/// </summary>
		public override string ProfileName { get { return (Profile); } }

		/// <summary>
		/// Modify a set of parameters defining an effect.
		/// </summary>
		/// <param name="shaderParameters">
		/// A <see cref="ColladaShaderParameters"/> that hols the current parameters for defining a
		/// COLLADA effect.
		/// </param>
		internal override void CompileShaderParameters(ColladaShaderParameters shaderParameters)
		{
			if (shaderParameters == null)
				throw new ArgumentNullException("shaderParameters");

			// Shader program
			shaderParameters.ShaderProgram = ShaderLibrary.CreateShaderProgram(shaderParameters.ShaderCompiler, "StandardShader");
			// Technique parameters
			Technique.CompileShaderParameters(shaderParameters);
		}

		/// <summary>
		/// Collada 'profile_COMMON' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeId = "id";

		/// <summary>
		/// Collada 'profile_COMMON' child element name (1.4).
		/// </summary>
		private const string ColladaElementAsset = "asset";

		/// <summary>
		/// Collada 'profile_COMMON' child element name (1.4).
		/// </summary>
		private const string ColladaElementImage = "image";

		/// <summary>
		/// Collada 'profile_COMMON' child element name (1.4).
		/// </summary>
		private const string ColladaElementNewParam = "newparam";

		/// <summary>
		/// Collada 'profile_COMMON' child element name (1.4).
		/// </summary>
		private const string ColladaElementTechnique = "technique";

		/// <summary>
		/// Collada 'profile_COMMON' child element name (1.4).
		/// </summary>
		private const string ColladaElementExtra = "extra";

		#endregion
	}
}
